#include "DeclManager.h"
#include "FileSystem.h"
#include "DictUtil.h"
#include "../infLib/infLib.h"

class DeclLocal: public Decl, public inf::Dict {
public:
    const char*     GetName() const {
        return name.c_str();
    }

    int             GetNumKeyvalues() const {
        return get_num_keyvalues();
    }

    const KeyValue  GetKeyValue(int i) const {
        const inf::KeyValue* kv = get_keyvalues( i );
        KeyValue result = { kv->get_key().c_str(), kv->get_value().c_str() };
        return result;
    }

    const KeyValue  FindKey( const char* key ) const {
        const inf::KeyValue* kv = find_key( key );
        KeyValue result = { kv->get_key().c_str(), kv->get_value().c_str() };
        return result;
    }

    int             FindKeyIndex( const char* key ) const {
        return find_key_index( key );
    }

    void            GetString( const char* key, const char*& value, const char *defaultString = "" ) const {
        const inf::KeyValue *kv = find_key( key );
        if ( kv ) {
            value = kv->get_value().c_str();
        }
        value = defaultString;
    }

    void            GetFloat( const char *key, float& value, const char *defaultString = "0" ) const {
        value = static_cast< float >( inf::Str::to_float( get_string( key, defaultString ) ) );
    }

    void            GetInt( const char *key, int& value, const char *defaultString = "0" ) const {
        value = inf::Str::to_integer( get_string( key, defaultString ) );
    }

    void            GetBool( const char *key, bool& value, const char *defaultString = "0") const {
        value = ( inf::Str::to_integer( get_string( key, defaultString ) ) != 0 );
    }

    void            GetVec3( const char *key, inf::Vec3& value, const char *defaultString = NULL ) const {
        get_Vec3( key, defaultString, value );
    }

    void            GetVec2( const char *key, inf::Vec2& value, const char *defaultString = NULL ) const {
        get_Vec2( key, defaultString, value );
    }

    void            GetVec4( const char *key, inf::Vec4& value, const char *defaultString = NULL ) const {
        get_Vec4( key, defaultString, value );
    }

    void            GetAngles( const char *key, inf::Angles& value, const char *defaultString = NULL ) const {
        get_Angles( key, defaultString, value );
    }

    void            GetMat3( const char *key, inf::Mat3& value, const char *defaultString = NULL ) const {
        get_Mat3( key, defaultString, value );
    }

    void            GetColor3( const char* key, inf::Color3& value, const char* defaultString = NULL ) const {
        get_Color3( key, defaultString, value );
    }
    void            GetColor4( const char* key, inf::Color4& value, const char* defaultString = NULL ) const {
        get_Color4( key, defaultString, value );
    }

    inf::Str        name;
};

// ==============================================================================
//! Decl type
//!
//! Used to read all dicts of one type
// ==============================================================================
class DeclType {
public:
    // ==============================================================================
    //! Constructor
    //!
    //! @param	typeName	Name to look for in the .decl file
    // ==============================================================================
    DeclType( const char *typeName );

    // ==============================================================================
    //! Solve inheritance
    //!
    //! @see	DeclParser::SolveInheritance
    // ==============================================================================
    void			SolveInheritance( void );

    inf::Str        			name;		//!< Type name
    inf::HashDict<DeclLocal>	declList;	//!< All dictionaries found

private:
    // ==============================================================================
    //! Do the inheritance for the specified declList entry
    //!
    //! @param	index	The index for the declList
    //!
    //! @see	SolveInheritance
    // ==============================================================================
    void			DoInheritance( int index );

    bool *			inheritanceSolved;	//!< Temp var to see what dictionary has already been solved
    inf::StrList	inheritancePast;	//!< History of all inheritances solved for this dict already,
    //! so we can avoid infinite inheritance
};

// ==============================================================================
//! .Decl file parser
// ==============================================================================
class DeclParser {
public:
    // ==============================================================================
    //! Constructor
    //!
    //! @param	flags	Flags passed to the lexer
    //! @note	LEXER_FULL_LINES will be ignored
    // ==============================================================================
    DeclParser( int flags=0 );

    // ==============================================================================
    //! Loads a file and parses it
    //!
    //! @param	filename	The (relative) file path
    //!
    //! @return	true if it succeeds, false if it fails
    //!
    //! Loads either the binary or the text version, depending on which is newer
    // ==============================================================================
    bool		LoadFile( const char *filename );

    // ==============================================================================
    //! Lex a file
    //!
    //! @param	filename	The (relative) file path
    //!
    //! @return	true if it succeeds, false if it fails
    // ==============================================================================
    bool		LexFile( const char *filename );

    // ==============================================================================
    //! Lex raw data
    //!
    //! @param	dataName	Name of the data ( for error messages )
    //! @param	data		Raw data (text)
    //! @param	size		The size of the data
    //!
    //! @return	true if it succeeds, false if it fails
    // ==============================================================================
    bool		LexData( const char *dataName, const inf::byte *data, int size );

    // ==============================================================================
    //! Load from a binary file
    //!
    //! @param	filename	The (relative) file path
    //!
    //! @return	true if it succeeds, false if it fails
    // ==============================================================================
    bool		BinaryFile( const char *filename );

    // ==============================================================================
    //! Load from a binary file
    //!
    //! @param	file	the file to read from
    //!
    //! @return	true if it succeeds, false if it fails
    // ==============================================================================
    bool		BinaryFile( File *file );

    // ==============================================================================
    //! Adds a decl type
    //!
    //! @param	declType	The DeclType to add
    //!
    //! When parsing a .decl file, it looks for all DeclTypes names
    //! and adds the found dictionary to the DeclType matching the name
    // ==============================================================================
    void		AddDeclType( DeclType *declType );

    // ==============================================================================
    //! Solve all inheritance
    //!
    //! This is called once all wanted files have been lexed
    // ==============================================================================
    void		SolveInheritance( void );

    // ==============================================================================
    //! Convert the file from text to binary format for faster parsing
    //!
    //! @param	filename	The (relative) file path
    //!
    //! @return	true if it succeeds, false if it fails
    // ==============================================================================
    static bool	MakeBinary( const char *filename );

private:
    // ==============================================================================
    //! Parses the file loaded in the lexer
    //!
    //! @param	lexer	The lexer to use
    // ==============================================================================
    void		Parse( inf::Lexer &lexer );

    int					    lexerFlags;	//!< Flags passed to the lexer
    inf::HashDict<DeclType*>     declTypes;	//!< All DeclTypes to look for / fill with data
};

#define DECL_DESCRIPTOR_STR "BinDecl"
const int DECL_DESCRIPTOR_LENGTH = 7;

/*
==============================================================================

  DeclType

==============================================================================
*/

/*
================
DeclType::DeclType
================
*/
DeclType::DeclType( const char *typeName ) {
	name = typeName;
	inheritanceSolved = NULL;
}

/*
================
DeclType::SolveInheritance
================
*/
void DeclType::SolveInheritance( void ) {
	int num = declList.size();
	if ( num == 0 )
		return;

    inf::List<bool> buffer(num);
    buffer.ready_num(num);
	inheritanceSolved = &buffer[0];
    inf::memory_set( inheritanceSolved, 0, num * sizeof(bool) );
	for( int i=0; i<num; i++ ) {
		inheritancePast.clear();
		DoInheritance( i );
	}
	inheritanceSolved = NULL;
}

/*
================
DeclType::DoInheritance
================
*/
void DeclType::DoInheritance( int index ) {
	int inheritFrom;
    inf::KeyValue* lastMatched = NULL;
    const inf::KeyValue* matched = NULL;
    matched = declList[index].match_prefix( "inherit" );
	for( ; matched != NULL; matched = declList[index].match_prefix( "inherit", matched ) ) {
        const inf::Str& value = matched->get_value();
		if ( inheritancePast.find_element( value ) != NULL ) {
			//User::Error(ERR_LEXER_FAILURE, "Inheritance Problem: declaration is inheriting from itself", value.c_str() );
			return;
		}

		inheritancePast.append( value );

		inheritFrom = declList.find( value.c_str() );
		if ( inheritFrom == -1 ) { 
			//User::Error(ERR_LEXER_WARNING, Format("Could not find inheritance '$*' of type $*" ) << value << name, declList.GetKey(index).c_str() );
			continue;
		}

		if ( !inheritanceSolved[inheritFrom] )
			DoInheritance( inheritFrom );

		declList[index].set_defaults( &declList[inheritFrom] );
		inheritancePast.remove( inheritancePast.find_element( value ) );
	}
	inheritanceSolved[index] = true;
}

/*
==============================================================================

  DeclParser

==============================================================================
*/

DeclParser::DeclParser( int flags ) {
	lexerFlags = flags;
    if ( lexerFlags & inf::LEXER_FULL_LINES )
		lexerFlags &= ~inf::LEXER_FULL_LINES;
}

bool DeclParser::LoadFile( const char *filename ) {
	if ( fileSystem == NULL )
		return false;
    inf::Str binFilename(filename);
	binFilename += ".bin";
	bool binExists = fileSystem->ExistFile( binFilename.c_str() );
	bool txtExists = fileSystem->ExistFile( filename );
	if ( binExists && txtExists ) {
		if ( fileSystem->FileTime( binFilename.c_str() ) > fileSystem->FileTime( filename ) )
			return BinaryFile( binFilename.c_str() );
		return LexFile(filename);
	}
	else if ( binExists )
		return BinaryFile( binFilename.c_str() );
	else if ( txtExists )
		return LexFile( filename );
	return false;
}

bool DeclParser::LexFile( const char *filename ) {
    inf::Lexer lexer(lexerFlags);
	if ( !lexer.LoadFile( filename ) )
		return false;

	Parse(lexer);

	return false;
}

bool DeclParser::LexData( const char *dataName, const byte *data, int size ) {
    inf::Lexer lexer(lexerFlags);
	if ( !lexer.LoadData( dataName, data, size ) )
		return false;

    Parse(lexer);
    return true;
}

void DeclParser::Parse( inf::Lexer &lexer ) {
    DeclLocal *resultDict = NULL;

	bool getKeyValue = false;

	int index;
	const inf::Token *token;
    inf::Str key, value;

	const char *p;
	while ( (token = lexer.ReadToken()) != NULL ) {
		p = token->GetString();
		if ( p ) {
			if ( *p == '\0' )
				lexer.Error("Unexpected Empty Token");
			if ( !getKeyValue ) {
				index = declTypes.find(p);
				if ( index != -1 ) {
					value = lexer.ReadString();

					if ( value.is_empty() )
						lexer.Error("Empty name!");

                    inf::HashDict<DeclLocal> &result = declTypes[index]->declList;
					index = result.find(p);
                    if ( index == -1 ) {
						resultDict = &result[p];
                        resultDict->name = p;
                    } else {
						resultDict = &result[index];
						resultDict->clear();
					}
				} else {
					resultDict = NULL;
                    char message[256]={0};
                    inf::snPrintf( message, 256, "Unknown decl Type %s", p );
					lexer.Warning( message );
				}
				lexer.ExpectToken("{");
				getKeyValue = true;
			} else {
				if ( *p == '}' )
					getKeyValue = false;
				else if ( resultDict ) {
					key = p;
                    resultDict->set( key.c_str(), lexer.ReadString() );
				}
			}
		}
	}
    if ( getKeyValue ) {
        lexer.SetError( inf::LexerError::END_OF_FILE );
    }
}

bool DeclParser::BinaryFile( const char *filename ) {
    if ( fileSystem == NULL )
        return false;
    File *file = fileSystem->OpenFileRead( filename );
    if ( !file )
        return false;

    bool ret = BinaryFile( file );
    fileSystem->CloseFile( file );
    return ret;
}

bool DeclParser::BinaryFile( File *file ) {
	char descriptor[DECL_DESCRIPTOR_LENGTH];
	file->Read( descriptor, DECL_DESCRIPTOR_LENGTH );
    if ( inf::Str::cmpn( descriptor, DECL_DESCRIPTOR_STR, DECL_DESCRIPTOR_LENGTH ) != 0 )
		return false;

	return false;
}

void DeclParser::AddDeclType( DeclType *declType ) {
	declTypes[declType->name.c_str()] =  declType;
}

void DeclParser::SolveInheritance( void ) {
	int num = declTypes.size();
	for( int i=0; i<num; i++ )
		declTypes[i]->SolveInheritance();
}


bool DeclParser::MakeBinary( const char *filename ) {
	if ( fileSystem == NULL )
		return false;

    bool valid = inf::Str::check_extension( filename, "bin" );
    if( !valid )
        return false;

    inf::Lexer lexer;
	if ( !lexer.LoadFile( filename ) )
		return false;


	File *f = fileSystem->OpenFileWrite( filename );
	if ( !f )
		return false;

	f->Write( DECL_DESCRIPTOR_STR, DECL_DESCRIPTOR_LENGTH );

    inf::Dict dict;
	bool getKeyValue = false;

	const inf::Token *token;
    inf::Str key, value;

    inf::Str str;
	const char *p;
	while ( (token = lexer.ReadToken()) != NULL ) {
		//! @todo	maybe token should be stored as String, so we don't have to recalc len/bytelen
		p = token->GetString();
		if ( p ) {
			if ( *p == '\0' ) {
				lexer.Error("Unexpected Empty Token");
				return false;
			}
			if ( !getKeyValue ) {
				str = p;
                f->Write( str.c_str(), str.length() );
				value = lexer.ReadString();

				if ( value.is_empty() ) {
					lexer.Error("Empty name!");
					return false;
				}
                f->Write( value.c_str(), value.length() );

				lexer.ExpectToken("{");
				getKeyValue = true;
			} else {
				if ( *p == '}' ) {
					getKeyValue = false;

                    WriteToFileHandle( f, dict );
					dict.clear();
				}
				else {
					key = p;
					dict.set( key.c_str(), lexer.ReadString() );
				}
			}
		}
	}
    fileSystem->CloseFile( f );

	if ( getKeyValue ) {
		lexer.Error("Unexpected End Of File");
		return false;
	}
	return true;

}

class XDeclNode {
public:
    // ==============================================================================
    //! Default constructor
    // ==============================================================================
    XDeclNode();

    // ==============================================================================
    //! Get the name of this node
    //!
    //! @return	The name
    // ==============================================================================
    const char *	GetName( void ) const { return name.c_str(); }

    // ==============================================================================
    //! Get the dictionary of this node
    //!
    //! @return	Const reference to the dictionary
    // ==============================================================================
    const inf::Dict&	GetDict( void ) const { return dict; }

    // ==============================================================================
    //! Get the first child of this node
    //!
    //! @return	NULL if this node has no child, else the first child
    // ==============================================================================
    const XDeclNode*    GetFirstChild( void ) const { return firstChild; }

    // ==============================================================================
    //! Get the first child by name
    //!
    //! @param	name	The name of the node you are looking for
    //!
    //! @return	NULL if this node has no (direct) childs with this name, else the first child by name
    // ==============================================================================
    const XDeclNode*    GetFirstChildByName( const char *name ) const; // return first child that has this name.

    // ==============================================================================
    //! Get the next sibling node
    //!
    //! @return	NULL if there are no nodes left, else the next node
    // ==============================================================================
    const XDeclNode*    GetNext( void ) const { return next; }

    // ==============================================================================
    //! Get the next sibling node with the same name as this one
    //!
    //! @return	NULL if there are no nodes left, else the next node
    // ==============================================================================
    const XDeclNode*    GetNextByName( void ) const;

private:
    friend class XDeclParser;
    inf::Str    	name;			//!< The name
    inf::Dict		dict;			//!< The dictionary
    int             numChildren;	//!< Number of children
    XDeclNode*		firstChild;		//!< The first child
    XDeclNode*		lastChild;		//!< The last child
    XDeclNode*		next;			//!< The next sibling
};

// ==============================================================================
//! .XDecl file parser
//!
//! @todo	add granularity to pass to allocator
// ==============================================================================
class XDeclParser {
public:
    XDeclParser();

    // ==============================================================================
    //! Loads a file and parses it
    //!
    //! @param	filename	The (relative) file path
    //!
    //! @return	true if it succeeds, false if it fails
    //!
    //! Loads either the binary or the text version, depending on which is newer
    // ==============================================================================
    bool		LoadFile( const char *filename );

    // ==============================================================================
    //! Lex a file
    //!
    //! @param	filename	The (relative) file path
    //!
    //! @return	true if it succeeds, false if it fails
    // ==============================================================================
    bool		LexFile( const char *filename );

    // ==============================================================================
    //! Lex raw data
    //!
    //! @param	dataName	Name of the data ( for error messages )
    //! @param	data		Raw data (text)
    //! @param	size		The size of the data
    //!
    //! @return	true if it succeeds, false if it fails
    // ==============================================================================
    bool		LexData( const char *dataName, inf::byte *data, int size );

    // ==============================================================================
    //! Load from a binary file
    //!
    //! @param	filename	The (relative) file path
    //!
    //! @return	true if it succeeds, false if it fails
    // ==============================================================================
    bool		BinaryFile( const char *filename );

    // ==============================================================================
    //! Load from a binary file
    //!
    //! @param	file	the file to read from
    //!
    //! @return	true if it succeeds, false if it fails
    // ==============================================================================
    bool		BinaryFile( File *file );

    const XDeclNode*    GetRoot( void ) const { return &rootNode; }

    // ==============================================================================
    //! Get the first child of this item
    //!
    //! @return	NULL if it fails, else the first child
    // ==============================================================================
    const XDeclNode *GetFirstChild( void ) const { return rootNode.GetFirstChild(); }

    // ==============================================================================
    //! Get the first child by name
    //!
    //! @param	name	The name of the node you are looking for
    //!
    //! @return	NULL if this node has no (direct) childs with this name, else the first child by name
    // ==============================================================================
    const XDeclNode *GetFirstChildByName( const char *name ) const { return rootNode.GetFirstChildByName( name ); }

    // ==============================================================================
    //! Convert the file from text to binary format for faster parsing
    //!
    //! @param	filename	The (relative) file path
    //!
    //! @return	true if it succeeds, false if it fails
    // ==============================================================================
    static bool	MakeBinary( const char *filename );

private:

    // ==============================================================================
    //! Parses the file loaded in the lexer
    //!
    //! @param	lexer	The lexer to use
    // ==============================================================================
    void		Parse( inf::Lexer &lexer );

    // ==============================================================================
    //! Read a node and its children from a binary file
    //!
    //! @param	node	The node
    //! @param	f		The file
    // ==============================================================================
    void		ReadNodeAndChildren( XDeclNode *node, File *f );

    // ==============================================================================
    //! Write a node and its children to a binary file
    //!
    //! @param	node	The node
    //! @param	f		The file
    // ==============================================================================
    static void	WriteNodeAndChildren( const XDeclNode *node, File *f );

    XDeclNode rootNode;				//!< The root node
    inf::Allocator<XDeclNode> allocator;	//!< An allocator
};

#define XDECL_DESCRIPTOR_STR "BinXDecl"
const int XDECL_DESCRIPTOR_LENGTH = 8;


/*
==============================================================================

  XDeclNode

==============================================================================
*/

/*
================
XDeclNode::XDeclNode
================
*/
XDeclNode::XDeclNode() {
	numChildren = 0;
	firstChild = NULL;
	lastChild = NULL;
	next = NULL;
}

/*
================
XDeclNode::GetFirstChildByName

return first child that has this name.
================
*/
const XDeclNode *XDeclNode::GetFirstChildByName( const char *name ) const {
	XDeclNode *child = firstChild;
	while( child ) {
		if ( child->name.cmp(name, false) == 0 )
			return child;
		child = child->next;
	}
	return NULL;
}

/*
================
XDeclNode::GetNextByName

return next that has the same name.
================
*/
const XDeclNode *XDeclNode::GetNextByName( void ) const {
	XDeclNode *sibling = next;
	while( sibling ) {
		if ( sibling->name.cmp(name.c_str(), false) == 0 )
			return sibling;
		sibling = sibling->next;
	}
	return NULL;
}

/*
==============================================================================

  XDeclParser

==============================================================================
*/
XDeclParser::XDeclParser() {
    rootNode.name = "Root";
}

bool XDeclParser::LoadFile( const char *filename ) {
    if ( fileSystem == NULL )
        return false;

    inf::Str binFilename(filename);
    binFilename += ".bin";
    bool binExists = fileSystem->ExistFile( binFilename.c_str() );
    bool txtExists = fileSystem->ExistFile( filename );
    if ( binExists && txtExists ) {
        if ( fileSystem->FileTime( binFilename.c_str() ) > fileSystem->FileTime( filename ) )
            return BinaryFile( binFilename.c_str() );
        return LexFile(filename);
    }
    else if ( binExists )
        return BinaryFile( binFilename.c_str() );
    else if ( txtExists )
        return LexFile( filename );
    return false;
}


bool XDeclParser::LexFile( const char *filename ) {
    inf::Lexer lexer;
    if ( !lexer.LoadFile( filename ) )
        return false;

    Parse(lexer);
    return true;
}

bool XDeclParser::LexData( const char *dataName, byte *data, int size ) {
    inf::Lexer lexer;
    if ( !lexer.LoadData( dataName, data, size ) )
        return false;

    Parse(lexer);
    return true;
}

void XDeclParser::Parse( inf::Lexer &lexer ) {
    const inf::Token *token;
    inf::Str name, value;
    XDeclNode *currentNode = &rootNode;
    XDeclNode *newNode;
    bool getKeyValue = false;
    bool addNode;
    inf::Stack<XDeclNode*> nodeStack;

    const char *p;
    while ( (token = lexer.ReadToken()) != NULL ) {
        p = token->GetString();
        if ( p ) {
            if ( *p == '\0' )
                lexer.Error("Unexpected Empty Token");

            if ( !getKeyValue ) {
                if ( inf::Str::cmp( p, "}" ) == 0 ) {
                    currentNode = nodeStack.top();
                    nodeStack.pop();
                } else {
                    name = p;
                    addNode = false;
                    if ( lexer.CheckToken("=") ) {
                        currentNode->dict.set( name.c_str(), lexer.ReadString() );
                        lexer.ExpectToken(";");
                    } else if ( lexer.CheckToken("(") ) {
                        addNode = true;
                        getKeyValue = true;
                    } else if ( lexer.CheckToken("{") ) {
                        addNode = true;
                    } else {
                        lexer.Error("Syntax Error, was expecting '(', '=' or '{'");
                    }
                    if ( addNode ) {    // round BUG!!!
                        newNode = allocator.alloc();
                        newNode->name = name;
                        currentNode->numChildren++;
                        if ( currentNode->firstChild == NULL )
                            currentNode->firstChild = newNode;
                        else
                            currentNode->lastChild->next = newNode;
                        currentNode->lastChild= newNode;
                        nodeStack.push( currentNode );
                        currentNode = newNode;
                    }
                }
            } else  {
                name = p;
                lexer.ExpectToken("=");
                currentNode->dict.set( name.c_str(), lexer.ReadString() );
                if ( !lexer.CheckToken(",") ) {
                    lexer.ExpectToken(")");
                    if ( lexer.CheckToken(";") ) {
                        currentNode = nodeStack.top();
                        nodeStack.pop();
                        getKeyValue = false;
                    } else if ( lexer.CheckToken("{") ) {
                        getKeyValue = false;
                    } else {
                        lexer.Error("Syntax Error, was expecting ';' or '{'");
                    }
                }
            }
        }
    }
    if ( getKeyValue || nodeStack.size() ) {
        inf::error( "End of file!\n" );
    }
}

bool XDeclParser::BinaryFile( const char *filename ) {
    if ( fileSystem == NULL )
        return false;

    File *file = fileSystem->OpenFileRead( filename );
    if ( !file )
        return false;

    bool ret = BinaryFile( file );
    fileSystem->CloseFile( file );
    return ret;
}

bool XDeclParser::BinaryFile( File *file ) {
    char descriptor[XDECL_DESCRIPTOR_LENGTH];
    file->Read( descriptor, XDECL_DESCRIPTOR_LENGTH );
    if ( inf::Str::cmpn( descriptor, XDECL_DESCRIPTOR_STR, XDECL_DESCRIPTOR_LENGTH ) != 0 )
        return false;

    ReadNodeAndChildren( &rootNode, file );
    return true;
}

void XDeclParser::ReadNodeAndChildren( XDeclNode *node, File *f ) {
    XDeclNode *newNode;
    node->numChildren = f->ReadUnsignedInt();
    for( int i=0; i<node->numChildren; i++ ) {
        newNode = allocator.alloc();
        if ( node->firstChild == NULL )
            node->firstChild = newNode;
        else
            node->lastChild->next = newNode;
        node->lastChild= newNode;

        f->ReadString( newNode->name );
        ReadFromFileHandle( newNode->dict, f );

        ReadNodeAndChildren( newNode, f );
    }
}

bool XDeclParser::MakeBinary( const char *filename ) {
    if ( fileSystem == NULL )
        return false;

    bool valid = inf::Str::check_extension( filename, "bin" );
    if( !valid )
        return false;

    XDeclParser parser;
    if ( !parser.LexFile( filename ) )
        return false;

    File *f = fileSystem->OpenFileWrite( filename );
    if ( !f )
        return false;

        f->Write( XDECL_DESCRIPTOR_STR, XDECL_DESCRIPTOR_LENGTH );

        const XDeclNode *node = parser.GetFirstChild();
        f->WriteUnsignedInt( parser.rootNode.numChildren );
        if ( node->numChildren )
            WriteNodeAndChildren( node, f );

        fileSystem->CloseFile( f );
        return true;
}


void XDeclParser::WriteNodeAndChildren( const XDeclNode *node, File *f ) {
    while( node ) {
        f->WriteString( node->name );
        WriteToFileHandle( f, node->GetDict() );

        f->WriteUnsignedInt( node->numChildren );
        if ( node->numChildren )
            WriteNodeAndChildren( node->GetFirstChild(), f );
        node = node->GetNext();
    }
}

typedef inf::Pair<DeclType*, DeclSeq> DeclTypeEntity;
typedef inf::List<DeclTypeEntity> DeclTypeEntries;

class DeclManagerLocal: public DeclManager {
public:
    DeclManagerLocal();
    ~DeclManagerLocal();

    bool            Init();
    void            Shutdown();

    bool            ParsePath( const char* path );
    void            ClearDecls();


    int             TypeNum() const;
    const char*     GetTypeName( int iType ) const;
    const DeclSeq&  GetDeclSeq( int iType ) const;

    int             DeclTotalNum() const;
    const Decl*     FindDeclFrom( const char* name, const char* typeName = NULL ) const;
    int             DeclNum( int iType ) const;
    const Decl*     GetDeclFromTypeIndex( int iDecl, int iType ) const;
private:
    DeclTypeEntries    declTypeEntries;
    DeclParser        parser;
};

DeclManagerLocal declManagerStatic;
DeclManager* declManager = &declManagerStatic;

static const char* const DeclTypeTable[] = {
    "Texture",
    "Program",
    "Material",
    "Model",
    "GameConfig",
    NULL
};

DeclManagerLocal::DeclManagerLocal()
{

}

DeclManagerLocal::~DeclManagerLocal()
{

}

bool DeclManagerLocal::Init()
{
    const char*const* typeName = DeclTypeTable;

    while( *typeName ) {
        DeclTypeEntity ent;
        ent.first = new DeclType( *typeName );
        ent.second.clear();

        declTypeEntries.append( ent );
        parser.AddDeclType( ent.first );

        ++typeName;
    }

    return true;
}

void DeclManagerLocal::Shutdown()
{
    DeclTypeEntries::const_iterator it = declTypeEntries.begin();
    for( ; it != declTypeEntries.end(); ++it ) {
        if( it->first ) {
            delete it->first;
        }
    }
    declTypeEntries.clear();
}

bool            DeclManagerLocal::ParsePath( const char* path ) {
    assert( path );

    FileList    declFileList;
    const int num = fileSystem->ListFiles(declFileList, path, "decl");
    if( num <= 0 )
        return false;

    const char* fileName = NULL;
    for( int i=0; i<num; ++i ) {
        fileName = declFileList.GetFile( i );
        parser.LoadFile(fileName);
        parser.SolveInheritance();
    }

    // build DeclSeq's
    Decl* decl = NULL;
    const inf::List<DeclLocal>* decls = NULL;
    DeclSeq* declSeq = NULL;
    DeclTypeEntries::iterator it = declTypeEntries.begin();
    for( ; it!=declTypeEntries.end(); ++it ) {
        decls = &(it->first->declList.GetEntries());
        const int declNum = decls->size();
        declSeq = &(it->second);
        declSeq->ready_num(declNum);

        for( int i=0; i<declNum; ++i ) {
            (*declSeq)[i] = const_cast<DeclLocal*>( &( (*decls)[i] ) );
        }
    }

    return true;
}

void            DeclManagerLocal::ClearDecls() {
    DeclType*   declType = NULL;
    for( int i=0; i<declTypeEntries.size(); ++i ) {
        declType = declTypeEntries[i].first;
        declType->declList.clear();
    }
}

int             DeclManagerLocal::TypeNum() const {
    return declTypeEntries.size();
}

const char*     DeclManagerLocal::GetTypeName( int iType ) const {
    assert( iType >= 0 );
    assert( iType < declTypeEntries.size() );

    return declTypeEntries[iType].first->name.c_str();
}

const DeclSeq&  DeclManagerLocal::GetDeclSeq( int iType ) const {
    assert( iType >= 0 );
    assert( iType < declTypeEntries.size() );
    return declTypeEntries[iType].second;
}

int             DeclManagerLocal::DeclTotalNum() const {
    int totalNum = 0;
    DeclType*   declType = NULL;
    for( int i=0; i<declTypeEntries.size(); ++i ) {
        declType = declTypeEntries[i].first;
        totalNum += declType->declList.size();
    }
    return totalNum;
}

const Decl*     DeclManagerLocal::FindDeclFrom( const char* name, const char* typeName ) const {
    DeclType*   declType = NULL;
    DeclLocal*  decl = NULL;
    int exist = inf::HashIndex::NULL_INDEX;

    if( typeName ) {
        for( int i=0; i<declTypeEntries.size(); ++i ) {
            declType = declTypeEntries[i].first;

            if( declType->name.cmp(typeName, false)==0 ) {
                // found the type

                exist = declType->declList.find( name, false );
                if( exist != inf::HashIndex::NULL_INDEX )   // found the decl
                    decl = &( declType->declList[ exist ] );
            }
        }
    }else{
        for( int i=0; i<declTypeEntries.size(); ++i ) {
            declType = declTypeEntries[i].first;

            exist = declType->declList.find( name, false );
            if( exist != inf::HashIndex::NULL_INDEX )   // found the decl
                decl = &( declType->declList[ exist ] );
        }
    }


    return decl;
}

int             DeclManagerLocal::DeclNum( int iType ) const {
    assert( iType >= 0 );
    assert( iType < declTypeEntries.size() );

    return declTypeEntries[iType].first->declList.size();
}

const Decl*     DeclManagerLocal::GetDeclFromTypeIndex( int iDecl, int iType ) const {
#ifdef INF_DEBUG
    const int declNum = DeclNum( iType );
#endif
    assert( iDecl >=0 );
    assert( iDecl < declNum );
        
    return &( declTypeEntries[iType].first->declList[ iDecl ] );
}
